package com.baohua.util;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 数据工具类, 对数据的转换、克隆、拷贝
 * @author czp
 *
 */

public class BeanUtils {

	 /**
	   * Java原数据类型对应对象
	   */
	  private static Map primaryTypeObjects = new HashMap();
	  static
	  {
	    primaryTypeObjects.put(boolean.class, Boolean.class);
	    primaryTypeObjects.put(char.class, Character.class);
	    primaryTypeObjects.put(byte.class, Byte.class);
	    primaryTypeObjects.put(short.class, Short.class);
	    primaryTypeObjects.put(int.class, Integer.class);
	    primaryTypeObjects.put(long.class, Long.class);
	    primaryTypeObjects.put(float.class, Float.class);
	    primaryTypeObjects.put(double.class, Double.class);
	  }

	  /**
	   * <pre>
	   * Java原数据类型业务分类
	   * </pre>
	   * 
	   * @author <a href="mailto:qiucy@sf-express.com">Jack Qiu</a>
	   * @version $Revision:1.0.0, $Date: 2007-9-17 14:21:46 $
	   */
	  private enum DATA_TYPE
	  {
	    BOOLEAN(boolean.class, Boolean.class), STRING(char.class, Character.class,
	        String.class), NUMBER(byte.class, Byte.class, short.class, Short.class,
	        int.class, Integer.class, long.class, Long.class, float.class,
	        Float.class, double.class, Double.class), OBJECT;

	    private Class<?>[] classes;

	    /**
	     * 分类定义
	     * 
	     * @param classes
	     *          该分类包含对象组
	     */
	    DATA_TYPE(Class<?>... classes)
	    {
	      this.classes = classes;
	    }

	    /**
	     * 是否包含指定的类
	     * 
	     * @param clazz
	     * @return
	     */
	    public boolean haveClass(Class<?> clazz)
	    {
	      for (Class<?> haveClass : classes)
	      {
	        if (haveClass.equals(clazz))
	        {
	          return true;
	        }
	      }

	      return false;
	    }
	  };

	  /**
	   * 获得数据类型对应Java对象类
	   * 
	   * @param requireClass
	   * @return
	   */
	  public static Class<?> getObjectType(Class<?> requireClass)
	  {
	    if (primaryTypeObjects.containsKey(requireClass))
	    {
	      return (Class) primaryTypeObjects.get(requireClass);
	    }
	    else
	    {
	      return requireClass;
	    }
	  }

	  /**
	   * 是否布尔类
	   * 
	   * @param clazz
	   * @return
	   */
	  public static boolean isBoolean(Class<?> clazz)
	  {
	    return DATA_TYPE.BOOLEAN.haveClass(clazz);
	  }

	  /**
	   * 是否布尔字符串
	   * 
	   * @param string
	   * @return
	   */
	  public static boolean isBoolean(String string)
	  {
	    try
	    {
	      Boolean.parseBoolean(string);
	      return true;
	    }
	    catch (Exception e)
	    {
	      return false;
	    }
	  }

	  /**
	   * 是否数值类
	   * 
	   * @param clazz
	   * @return
	   */
	  public static boolean isNumber(Class<?> clazz)
	  {
	    return DATA_TYPE.NUMBER.haveClass(clazz);
	  }

	  /**
	   * 是否长整形字符串
	   * 
	   * @param string
	   * @return
	   */
	  public static boolean isInteger(String string)
	  {
	    try
	    {
	      Integer.parseInt(string);
	      return true;
	    }
	    catch (Exception e)
	    {
	      return false;
	    }
	  }

	  /**
	   * 是否字符串类
	   * 
	   * @param clazz
	   * @return
	   */
	  public static boolean isString(Class<?> clazz)
	  {
	    return DATA_TYPE.STRING.haveClass(clazz);
	  }

	  /**
	   * 根据类名构造实例
	   * 
	   * @param clazz
	   * @return
	   */
	  public static Object getObjectFromClazz(String clazz)
	  {
	    try
	    {
	      Class eventClass = getClassFromClazz(clazz);
	      return eventClass.getDeclaredConstructor((Class[]) null).newInstance(
	          (Object[]) null);
	    }
	    catch (Exception e)
	    {
	      e.printStackTrace();
	      System.err.println("实例化类时出错" + clazz);
	      return null;
	    }
	  }

	  /**
	   * 根据类名加载类
	   * 
	   * @param clazz
	   * @return
	   */
	  public static Class getClassFromClazz(String clazz)
	  {
	    try
	    {
	      return BeanUtils.class.getClassLoader().loadClass(clazz);
	    }
	    catch (Exception e)
	    {
	      e.printStackTrace();
	      System.err.println("实例化类时出错" + clazz);
	      return null;
	    }
	  }

	  /**
	   * 根据类名，方法名及参数类型获得方法对象
	   * 
	   * @param clazz
	   * @param methodName
	   * @param parameterTypes
	   *          参数类型组
	   * @return
	   */
	  public static Method getMethodByName(Class<?> clazz, String methodName,
	      Class<?>[] parameterTypes)
	  {
	    Class<?> objectClazz = BeanUtils.getObjectType(clazz);

	    Method[] methods = objectClazz.getMethods();

	    for (Method method : methods)
	    {
	      if (method.getName().equals(methodName)
	          && Arrays.equals(method.getParameterTypes(), parameterTypes))
	      {
	        return method;
	      }
	    }

	    throw new RuntimeException(objectClazz + "不存在参数为["
	        + parameterTypes.toString() + "]的方法 - " + methodName);
	  }

	  /**
	   * 获得指定取值方法的相应属性名
	   * 
	   * @param modelMethod
	   * @return
	   */
	  public static String getPropertyNameByGetMethod(Method beanReadMethod)
	  {
	    String methodName = beanReadMethod.getName();
	    String property = null;

	    if (isBoolean(beanReadMethod.getReturnType()))
	    {
	      if (methodName.startsWith("is"))
	      {
	        property = methodName.substring(2, 3).toLowerCase()
	            + methodName.substring(3);
	      }
	    }
	    else
	    {
	      if (methodName.startsWith("get"))
	      {
	        property = methodName.substring(3, 4).toLowerCase()
	            + methodName.substring(4);
	      }
	    }

	    /**
	     * 校验是否符合JavaBean规范
	     */
	    if (property != null)
	    {
	      Method orgBeanReadMethod = getReadMethod(property, beanReadMethod
	          .getDeclaringClass());

	      if (!beanReadMethod.equals(orgBeanReadMethod))
	      {
	        property = null;
	        throw new RuntimeException("校验失败" + methodName);
	      }
	    }

	    if (property == null)
	    {
	      throw new RuntimeException("方法未找到相对应属性名" + methodName);
	    }

	    return property;
	  }

	  /**
	   * 获得模型取值方法
	   * 
	   * @param property
	   * @return
	   */
	  public static Method getReadMethod(String property, Class<?> beanClass)
	  {
	    PropertyDescriptor propertyDescriptor = null;

	    try
	    {
	      propertyDescriptor = new PropertyDescriptor(property, beanClass);
	    }
	    catch (IntrospectionException introspectionException)
	    {
	      throw new RuntimeException(beanClass + "属性不存在或未提供标准存取方式：" + property);
	    }

	    return propertyDescriptor.getReadMethod();
	  }

	  /**
	   * 获得模型写方法
	   * 
	   * @param property
	   * @param beanClass
	   * @return
	   */
	  public static Method getWriteMethod(String property, Class<?> beanClass)
	  {
	    PropertyDescriptor propertyDescriptor = null;

	    try
	    {
	      propertyDescriptor = new PropertyDescriptor(property, beanClass);
	    }
	    catch (IntrospectionException introspectionException)
	    {
	      throw new RuntimeException(beanClass + "属性不存在或未提供标准存取方式：" + property);
	    }

	    return propertyDescriptor.getWriteMethod();
	  }

	  /**
	   * 获得Bean属性值，支持级联
	   * 
	   * @param property
	   * @param bean
	   * @return
	   */
	  public static Object getPropertyValue(String property, Object bean)
	  {
	    try
	    {
	      String[] properties = property.split("\\.");

	      if (properties.length > 1)
	      {
	        bean = getPropertyValue(properties[0], bean);
	        if (bean == null)
	        {
	          System.out.println("取" + properties[0] + "值时返回空");
	        }
	      }

	      Method readMethod = getReadMethod(properties[properties.length - 1], bean
	          .getClass());
	      return readMethod.invoke(bean);
	    }
	    catch (Exception e)
	    {
	      System.err.println("在从[" + bean + "]取属性[" + property + "]的值时发生错误");
	      e.printStackTrace();
	      throw new RuntimeException("在从[" + bean + "]取属性[" + property + "]的值时发生错误");
	    }
	  }

	  /**
	   * 设置Bean属性值，支持级联
	   * 
	   * @param property
	   * @param bean
	   * @param value
	   */
	  public static void setPropertyValue(String property, Object bean, Object value)
	  {
	    try
	    {
	      String[] properties = property.split("\\.");

	      if (properties.length > 1)
	      {
	        bean = getPropertyValue(properties[0], bean);
	      }

	      Method writeMethod = getWriteMethod(properties[properties.length - 1],
	          bean.getClass());

	      Object convertObject = null;
	      if (value instanceof Date)
	      {
	        convertObject = value;
	      }
	      else if (value != null)
	      {
	        convertObject = convertToObject(
	            getReadMethod(properties[properties.length - 1], bean.getClass())
	                .getReturnType(), value.toString());
	      }

	      writeMethod.invoke(bean, convertObject);
	    }
	    catch (Exception e)
	    {
	      // e.printStackTrace();
	      throw new RuntimeException("在为[" + bean + "]设置属性[" + property
	          + "]的值时发生错误");
	    }
	  }

	  /**
	   * 将字符串转化为指定的数据类型
	   * 
	   * @param clazz
	   * @param value
	   * @return
	   */
	  public static Object convertToObject(Class clazz, String value)
	  {
	    if (clazz == String.class)
	    {
	      return value;
	    }

	    Class<?> objectClass = BeanUtils.getObjectType(clazz);
	    Method method = getMethodByName(objectClass, "valueOf", new Class[]
	    { String.class });

	    try
	    {
	      // 带字符串构造方法
	      Constructor<?> c = objectClass.getConstructor(new Class[]
	      { String.class });
	      // 创建实例
	      Object o = c.newInstance(new Object[]
	      { "0" });
	      // 执行valueOf方法，返回所需类型结果
	      return method.invoke(o, new Object[]
	      { value });
	    }
	    catch (Exception e)
	    {
	      throw new RuntimeException("在转换[" + value + "]为类型[" + objectClass
	          + "]时发生错误：" + e.getMessage());
	    }
	  }

	  /**
	   * 根据属性值定位Bean
	   * 
	   * @param property
	   * @param value
	   * @return
	   */
	  public static Object locateBean(List<?> beans, String property,
	      Object propertyValue)
	  {
	    if ((propertyValue == null) || (beans == null) || (beans.size() == 0))
	    {
	      return null;
	    }

	    for (Object bean : beans)
	    {
	      Object beanValue = BeanUtils.getPropertyValue(property, bean);

	      /**
	       * 批配数值类型
	       */
	      if (BeanUtils.isNumber(propertyValue.getClass())
	          && BeanUtils.isString(beanValue.getClass()))
	      {
	        beanValue = BeanUtils.convertToObject(propertyValue.getClass(),
	            beanValue.toString());
	      }

	      /**
	       * 对对象类型和原数据类型均进行比较
	       */
	      if (propertyValue.equals(beanValue) || (propertyValue == beanValue))
	      {
	        return bean;
	      }
	    }

	    return null;
	  }

	  /**
	   * 在两个对象中拷贝属性值，主要用于从父类向子类转化用 为了避免错误，对集合类属性不进行拷贝
	   * 
	   * @param source
	   * @param target
	   */
	  public static void copyProperty(Object source, Object target)
	  {
	    String property = null;
	    for (Method method : source.getClass().getMethods())
	    {
	      try
	      {
	        if ((property = getPropertyNameByGetMethod(method)) != null)
	        {
	          Object value = getPropertyValue(property, source);

	          /**
	           * 不拷贝集合类属性
	           */
	          if (!(value instanceof Collection))
	          {
	            setPropertyValue(property, target, value);
	          }
	        }
	      }
	      catch (Exception e)
	      {
	        // e.printStackTrace();
	      }
	    }
	  }


	  /**
	   * 比较两个对象值是否相等
	   * 
	   * <pre>
	   * 该方法不支持集合比较
	   * </pre>
	   * 
	   * @param object
	   * @param otherObject
	   * @return
	   * @author Jack.Qiu
	   * @since 2008-5-27
	   */
	  public static boolean compareObject(Object object, Object otherObject)
	  {
	    /**
	     * 空值判断
	     */
	    if ((object == null) || (otherObject == null))
	    {
	      return object == otherObject;
	    }

	    /**
	     * 类判断
	     */
	    if (!object.getClass().equals(otherObject.getClass()))
	    {
	      return false;
	    }

	    if ((object instanceof Collection) || (otherObject instanceof Collection))
	    {
	      return false;
	    }

	    String property = null;
	    for (Method method : object.getClass().getMethods())
	    {
	      try
	      {
	        if ((property = getPropertyNameByGetMethod(method)) != null)
	        {
	          Object value = getPropertyValue(property, object);

	          /**
	           * 先比较非集合类属性
	           */
	          if (!(value instanceof Collection))
	          {
	            Object otherValue = getPropertyValue(property, otherObject);

	            if ((value == null) || (otherValue == null))
	            {
	              if ((value != null) || (otherValue != null))
	              {
	                return false;
	              }
	            }

	            if (value != null)
	            {
	              if (!value.equals(otherValue))
	              {
	                return false;
	              }
	            }
	          }
	          else
	          {
	            Collection collection = (Collection) value;
	            Collection otherCollection = (Collection) getPropertyValue(
	                property, otherObject);

	            if ((collection == null) || (otherCollection == null))
	            {
	              if ((collection != null) || (otherCollection != null))
	              {
	                return false;
	              }
	            }

	            if (collection.size() != otherCollection.size())
	            {
	              return false;
	            }

	            for (int i = 0; i < collection.size(); i++)
	            {
	              Object child = collection.toArray()[i];
	              Object otherChild = otherCollection.toArray()[i];

	              if (!compareObject(child, otherChild))
	              {
	                return false;
	              }
	            }
	          }
	        }
	      }
	      catch (Exception e)
	      {
	        // e.printStackTrace();
	      }
	    }

	    return true;
	  }

	  /**
	   * 打印对象属性
	   * 
	   * @param source
	   * @param target
	   */
	  public static void printProperty(Object obj, PrintStream... outs)
	  {
	    String property = null;
	    for (Method method : obj.getClass().getMethods())
	    {
	      try
	      {
	        if ((property = getPropertyNameByGetMethod(method)) != null)
	        {
	          Object value = getPropertyValue(property, obj);

	          PrintStream out = System.out;

	          if ((outs != null) && (outs.length == 1))
	          {
	            out = outs[0];
	          }

	          out.println(property + " : " + value);
	        }
	      }
	      catch (Exception e)
	      {
	      }
	    }
	  }
	
}
